package xpn.platform.modules.stamp;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.security.MessageDigest;

import javax.imageio.ImageIO;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import xpn.platform.common.config.XpnPlatformConfig;
import xpn.platform.common.exception.XpnBusinessException;
import xpn.platform.common.exception.XpnExceptionCodeEnum;
import xpn.platform.common.util.Tool;
import xpn.platform.modules.attachment.AttachmentService;

@Service
public class StampServiceImpl implements StampService {
    @Autowired
    XpnPlatformConfig xpnPlatformConfig;

    @Autowired
    AttachmentService attachmentService;

    @Override
    public void stamp(String entityLink, String sealLink,String sealCategory,Long userId) throws Throwable {

        //找到印章文件的路径
        String sealFolderPath = attachmentService.getAttachmentFolder(sealLink, sealCategory);
        File sealFolder = new File(sealFolderPath);
        File sealFiles[] = sealFolder.listFiles();
        if (sealFiles.length==0) {
            throw new XpnBusinessException(XpnExceptionCodeEnum.BUSINESS_EXCEPTION_HTTP_STATUS, "未上传印章文件!");
        }
        String sealFileName="";
        for (int i = 0; i < sealFiles.length; i++) {
            File fs = sealFiles[i];
            if (!fs.isDirectory()) {
                sealFileName=fs.getName();
            }
        }
        String sealFilePath=sealFolderPath+"/"+sealFileName;


        File sealFile = new File(sealFilePath);  //得到印章文件
        Image sealImg = ImageIO.read(sealFile);//文件转化为图片
        Integer sealImgWidth = sealImg.getWidth(null);//获取图片的宽
        Integer sealImgHeight = sealImg.getHeight(null);//获取图片的高

        // 加水印
        BufferedImage bufImg = new BufferedImage(sealImgWidth, sealImgHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = bufImg.createGraphics();
        // ----------  增加下面的代码使得背景透明  -----------------
        bufImg = g.getDeviceConfiguration().createCompatibleImage(
                sealImgWidth,sealImgHeight,Transparency.TRANSLUCENT);
        g .dispose();
        g  = bufImg.createGraphics();
        // ----------  背景透明代码结束  -----------------

        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(
                sealImg.getScaledInstance(sealImgWidth,
                        sealImgHeight, Image.SCALE_SMOOTH), 0, 0,
                null);

        Color color=new Color(0,0,0); //水印色彩
        g.setColor(color); //根据图片的背景设置水印颜色
        Font font = new Font("微软雅黑", Font.PLAIN, 45);                     //水印字体
        g.setFont(font);
        //设置水印文字透明度
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
                0f));
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
        //设置日期水印的坐标
        String waterMarkDate=getDateString();
        Integer watermarkLength=getWatermarkLength(waterMarkDate, g);
        Integer x = (sealImgWidth - watermarkLength)/2;
        Integer y = sealImgHeight - sealImgHeight*2/8;
        g.drawString(waterMarkDate,  x , y);  //画出日期水印

        //设置编码水印的坐标
        font = new Font("微软雅黑", Font.PLAIN, 40);                     //水印字体
        g.setFont(font);
        String waterMarkNo=getMD5(entityLink+"-"+sealFileName+"-"+userId+"-"+waterMarkDate).toUpperCase();
        Integer watermarkNoLength=getWatermarkLength(waterMarkNo, g);
        Integer xNo = (sealImgWidth - watermarkNoLength)/2;
        Integer yNo = sealImgHeight - sealImgHeight*1/12;
        g.drawString(waterMarkNo, xNo, yNo);  //画出编码水印

        g.dispose();

        // 输出图片
        String outSealPath=attachmentService.getAttachmentFolder(entityLink, "seal")+"/seal.png";
        File oldFile=new File(outSealPath);
        if(oldFile.exists()){
            oldFile.delete();
        }
        FileOutputStream outImgStream = new FileOutputStream(outSealPath);
        ImageIO.write(bufImg, "png", outImgStream);
        outImgStream.flush();
        outImgStream.close();
    }

    public static String getMD5(String str) {
        try {
            // 生成一个MD5加密计算摘要
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 计算md5函数
            md.update(str.getBytes());
            // digest()最后确定返回md5 hash值，返回值为8为字符串。因为md5 hash值是16位的hex值，实际上就是8位的字符
            // BigInteger函数则将8位的字符串转换成16位hex值，用字符串来表示；得到字符串形式的hash值
            return new BigInteger(1, md.digest()).toString(16).substring(6, 24);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public Integer getWatermarkLength(String waterMarkContent, Graphics2D g) {
        return g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0, waterMarkContent.length());
    }

    public String getDateString() {
        Integer year=Tool.getYear();
        Integer month = Tool.getMonth();
        Integer day = Tool.getDay();
        String dateString=convertIntToCharacters(year)+"年"
                +convertIntToChinaCharacters(month)+"月"+convertIntToChinaCharacters(day)+"日";
        return dateString;
    }

    public String convertIntToChinaCharacters(Integer number){
        if(number<10) {
            return convertIntToCharacters(number);
        }
        else{
            String numStr="";
            char[] numChars = number.toString().toCharArray();
            if(numChars.length>=2){
                numStr=numStr+convertIntToCharacters(Integer.valueOf(String.valueOf(numChars[0])))+"十";
                numStr=numStr+convertIntToCharacters(Integer.valueOf(String.valueOf(numChars[1])));
            }
            return numStr;
        }
    }

    public String convertIntToCharacters(Integer number){
        String numStr="";
        char[] numChars = number.toString().toCharArray();
        for(char num:numChars){
            switch (num){
                case '0':numStr=numStr+"O";break;
                case '1':numStr=numStr+"一";break;
                case '2':numStr=numStr+"二";break;
                case '3':numStr=numStr+"三";break;
                case '4':numStr=numStr+"四";break;
                case '5':numStr=numStr+"五";break;
                case '6':numStr=numStr+"六";break;
                case '7':numStr=numStr+"七";break;
                case '8':numStr=numStr+"八";break;
                case '9':numStr=numStr+"九";break;
                default:break;
            }
        }
        return numStr;
    }
}
